//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//

#include "precomp.h"
#include <Pmpolicy.h>
#include "muxapi.h"
#include "ipm_api.h"


#include <ceddk.h>
#include "xllp_i2c.h"
#include "monahans.h"

#include <nkintr.h>
#include <bsp_cfg.h>

#include <serhw.h>
#include <16550.h>
#include "gsm0710_ioctrl.h"

//////////////////////////////////////////////////////////////////////////////
// Currently the one and only instance of the CPowerManager
//////////////////////////////////////////////////////////////////////////////

CPowerManager g_PowerManager;

//////////////////////////////////////////////////////////////////////////////
// Externals
//////////////////////////////////////////////////////////////////////////////

extern RHA_FUNCTION_LIST RHAFunctionList;

extern BOOL   g_fEmergencyCall;
extern UINT   g_iPPLMNBufferPos;
extern DWORD  g_rsiused;
extern INT    g_iNrCallInfo;
extern DWORD  g_dwSIMLockedState;
extern BOOL   g_bCINDIsActive;
extern UINT   g_iLastRSSI;
extern UINT   g_iLastSignal;
extern UINT   g_nRSSI;
extern UINT   g_nBER;
extern BOOL   g_fInitMicroTemp;

#ifdef RIL_FAKECSQ
extern volatile BOOL g_fFakeSignalStrength;
#endif

#ifdef RIL_USE_CSQ_NOTIFICATIONS
DWORD WINAPI ReSendSignalThreadProc(LPVOID pVoid);
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Class CPowerCmd
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerCmd::CPowerCmd(DWORD dwCmd, CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState, CEDEVICE_POWER_STATE OldPwrState, BOOL fEquCmd, BOOL fUrcInit) {
  SYNCBLOCK(g_csClosing);
  m_NewPwrState = NewPwrState;
  m_OldPwrState = OldPwrState;
  m_dwCmd = dwCmd;
  m_pHandle = pHandle;
  m_fUrcInit = fUrcInit;
  m_fEquCmd = fEquCmd;
  m_hFinishEvent = NULL;
  if (IsPowerCmd() && (NewPwrState >= D3)) {
    m_hFinishEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  }
  if (m_pHandle) {
    m_pHandle->GetCmdList()->Add(this);
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerCmd::~CPowerCmd() {
  SetEvent(m_hFinishEvent);
  CloseHandle(m_hFinishEvent);
}

//////////////////////////////////////////////////////////////////////////////
//
// Reset and return the internal finish event to assign to other instance.
//
// Return:
//  The internal finish event.
//
//////////////////////////////////////////////////////////////////////////////
HANDLE CPowerCmd::InheritFinishEvent(void) {
  HANDLE hRet = m_hFinishEvent;
  m_hFinishEvent = NULL;
  return hRet;
};

//////////////////////////////////////////////////////////////////////////////
//
// Class CPowerManager
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Public class implementation
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerManager::CPowerManager() {
  m_pRilHandle = NULL;
  m_hShutdownThread = NULL;
  m_hFlightmodeEvent = NULL;
  m_dwModemState = MODEMSTATE_SIEMENS_POWEROFF;
  m_dwNewModemState = m_dwModemState;
  m_dwOldModemState = m_dwModemState;
  m_dwInitUrcState = INVALID_MODEM_STATE;
  m_PowerState = D0;
  m_fOngoing = FALSE;
  m_fUrcInitialized = FALSE;
  m_fOffToAirplane = FALSE;
  m_fPowerOffForced = FALSE;
  m_fUnattendedMode = FALSE;
  m_fIdleTimerReset = FALSE;
  m_dwRegStatusCache = 0;
  m_dwGPRSRegStatusCache = 0;
  m_dwTimeLastOff = GetTickCount();
  m_nSMSPhase = 0;
  m_hCmdQueueThread = NULL;
  m_hATCmdRequeueEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  m_hRadioOnOffMutex = CreateEvent(NULL, TRUE, TRUE, NULL);
  m_hIdleResetLeaveEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  m_hCmdQueueExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  m_CmdQueue.Init(m_hCmdQueueExitEvent);
  InitializeCriticalSection(&m_csPowerState);
  InitializeCriticalSection(&m_csForcePower);
  InitializeCriticalSection(&m_csUnattended);
  m_IPMClientID = INVALID_CLIENT_ID;
}

//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerManager::~CPowerManager() {
  Deinit();
  CloseHandle(m_hIdleResetLeaveEvent);
  CloseHandle(m_hRadioOnOffMutex);
  CloseHandle(m_hATCmdRequeueEvent);
  CloseHandle(m_hCmdQueueExitEvent);
  DeleteCriticalSection(&m_csUnattended);
  DeleteCriticalSection(&m_csForcePower);
  DeleteCriticalSection(&m_csPowerState);
}

//////////////////////////////////////////////////////////////////////////////
//
// Initialize the class with required information.
//
// Params:
//  pRilHandle: Pointer to the connected CRilHandle instance which is needed
//              internal.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::Init(CRilHandle* pRilHandle) {
    SYNCBLOCK(m_csPowerState);
    m_pRilHandle= pRilHandle;  

    if (!InitIPM())
    {
        RILRetailTrace((TEXT("CPowerManager::Init: InitIPM Failed!\n")));
    }
    
    m_hCmdQueueThread = CreateThread(NULL, 0, CmdQueueThread, (LPVOID)this, 0, NULL);
    SwitchUnattendedMode(TRUE);
}

//////////////////////////////////////////////////////////////////////////////
//
// Tell the class that the information passed to Init() is no longer valid.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::Deinit(void) {
  SYNCBLOCK(m_csPowerState);
  SwitchUnattendedMode(FALSE);

  /* Rlease IPM Client */
  if (INVALID_CLIENT_ID != m_IPMClientID)
  {
      IPM_DeRegister(m_IPMClientID, 3000);
  }


  SetEvent(m_hCmdQueueExitEvent);
  WaitForSingleObject(m_hCmdQueueThread, POWER_LOCK_TIMEOUT);
  CloseHandle(m_hCmdQueueThread);
  EmptyCmdQueue();
  m_hCmdQueueThread= NULL;
  ForcePowerOff();
  m_pRilHandle= NULL;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enter a given power state.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  NewPwrState: The new power state to switch the module into.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterPowerState(CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState) {
CPowerCmd*            pCmd;
DWORD                 dwLastEquipmentState;
DWORD                 dwNewModemState;
DWORD                 dwNewModemStateDefault;
CEDEVICE_POWER_STATE  OldPwrState;
DWORD dwFFUARTSysIntr = SYSINTR_FFUART;

  if ((NewPwrState < D0) || (NewPwrState > D4)) {
    RILRetailTrace((TEXT("RilDrv: Unsupported Power-State D%d\r\n"), NewPwrState));
    SetLastError(ERROR_INVALID_PARAMETER);
    return FALSE;
  }

  EnterCriticalSection(&m_csPowerState);

  OldPwrState = m_PowerState;

  RILRetailTrace((TEXT("RilDrv: EnterPowerState(old: D%d, new: D%d)\r\n"), OldPwrState, NewPwrState));

  // Load the last equipment state from the registry
  if (pHandle)
  {
      if (!GetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, &dwLastEquipmentState)) {
        dwLastEquipmentState = RIL_EQSTATE_FULL;
      } else {
        switch (dwLastEquipmentState) {
          case RIL_EQSTATE_FULL:
          case RIL_EQSTATE_MINIMUM:
          case RIL_EQSTATE_DISABLETXANDRX:
            break;
          default:
            dwLastEquipmentState = RIL_EQSTATE_FULL;
            break;
        }
      }
  }
  else
  {
     /* This case is for RIL_Init Power Cmd */ 
     dwLastEquipmentState = RIL_EQSTATE_FULL;
  }

  
  // Get the default new module state
  switch (NewPwrState) {
    case D0:
    case D1:
    case D2:

      /* Disable wakeup from D3,D4 */
      KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &dwFFUARTSysIntr,sizeof(dwFFUARTSysIntr), NULL, 0, NULL);

      switch (dwLastEquipmentState) {
        case RIL_EQSTATE_MINIMUM:
          dwNewModemStateDefault = MODEMSTATE_SIEMENS_POWEROFF;
          break;
        case RIL_EQSTATE_DISABLETXANDRX:
          dwNewModemStateDefault = MODEMSTATE_SIEMENS_AIRPLANE;
          break;
        default: // RIL_EQSTATE_FULL
          dwNewModemStateDefault = MODEMSTATE_SIEMENS_POWERON;
          break;
      }
      break;

    case D3:

      /* Enable wakeup from D3 */
      KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &dwFFUARTSysIntr,  sizeof(dwFFUARTSysIntr), NULL, 0, NULL);        
      
      switch (dwLastEquipmentState) {
        case RIL_EQSTATE_MINIMUM:
          dwNewModemStateDefault = MODEMSTATE_SIEMENS_POWEROFF;
          break;
        case RIL_EQSTATE_DISABLETXANDRX:
          dwNewModemStateDefault = MODEMSTATE_SIEMENS_AIRPLANE;
          break;
        default: // RIL_EQSTATE_FULL
          dwNewModemStateDefault = DEFAULT_URCCONFIG;
          break;
      }
      break;

    case D4:

      /* Disable wakeup from D4 */
      KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &dwFFUARTSysIntr,  sizeof(dwFFUARTSysIntr), NULL, 0, NULL);        

      dwNewModemStateDefault = MODEMSTATE_SIEMENS_POWEROFF;
      break;
  }

  // Check if we missed an external power change
  if (!m_fOngoing && (m_dwNewModemState != MODEMSTATE_SIEMENS_POWEROFF)) {
    if (!RHAFunctionList.pfnRHA_IsRadioPwrOn()) {
      RILRetailTrace((TEXT("RilDrv: EnterPowerState() - Module powered off externally!\r\n")));
      // Tidy up internal states
      ForcePowerOff();
      pCmd = new CPowerCmd(MODEMSTATE_SIEMENS_FORCE_POWEROFF, pHandle, NewPwrState, OldPwrState, FALSE, FALSE);
      if (!m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
        delete pCmd;;
      }
    }
  }

  // First ask if our default power handling shall be overwritten
  dwNewModemState = RHAFunctionList.pfnRHA_SystemPowerChange(m_PowerState, NewPwrState, m_dwNewModemState, dwNewModemStateDefault, m_fOngoing, FALSE);

  if (!IS_VALID_MODEMSTATE(dwNewModemState)) {
    dwNewModemState = dwNewModemStateDefault;
  }

  // Store the new power state
  m_PowerState = NewPwrState;

  // Execute FORCE_POWEROFF immediately ...
  if (dwNewModemState == MODEMSTATE_SIEMENS_FORCE_POWEROFF) {
    // ... but we have to wait until pending commands has finished nevertheless ...
    ForcePowerOff();
    // ... so run through the usual command queue including wait also for FORCE_POWEROFF.
    // Otherwise there could be conflicts with aborted commands during next switch on.
  }

  // Now queue the command
  pCmd = new CPowerCmd(dwNewModemState, pHandle, NewPwrState, OldPwrState, FALSE, FALSE);
  LeaveCriticalSection(&m_csPowerState);
  if (!m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    delete pCmd;
    return FALSE;
  }

  // Register unattended mode for power state changes from D3 or below to D2 or above
  if ((OldPwrState >= D3) && (NewPwrState <= D2)) {
    SwitchUnattendedMode(TRUE);
  }

  DWORD ulRet = WaitForSingleObject(pCmd->GetFinishEvent(), POWER_LOCK_TIMEOUT);

  if (WAIT_TIMEOUT == ulRet)
  {
      RILRetailTrace((TEXT("RilDrv: WaitFor(pCmd->GetFinishEvent(), POWER_LOCK_TIMEOUT) Failed!\r\n")));    
      return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enter a given equipment state via the RIL equipment state interface.
//  
// Params:
//  pHandle   : Pointer to CRilInstanceHandle to be used for the operation.
//  dwNewState: The new equipment state to switch the module into.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterEquipmentState(CRilInstanceHandle* pHandle, DWORD dwNewState) {
CPowerCmd*  pCmd;
DWORD       dwNewModuleState;

  if ((dwNewState != RIL_EQSTATE_MINIMUM)         &&
      (dwNewState != RIL_EQSTATE_DISABLETXANDRX)  &&
      (dwNewState != RIL_EQSTATE_FULL)) {
    RILRetailTrace((TEXT("RilDrv: Unsupported Equipment-State %d\r\n"), dwNewState));
    return FALSE;
  }

  EnterCriticalSection(&m_csPowerState);

  g_fEmergencyCall = FALSE;
#ifdef RIL_FAKECSQ
  g_fFakeSignalStrength = FALSE;
#endif

  switch (dwNewState) {
    case RIL_EQSTATE_MINIMUM:
      RILRetailTrace((TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_MINIMUM)\r\n")));
      g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
      g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
      dwNewModuleState = MODEMSTATE_SIEMENS_POWEROFF;
      break;

    case RIL_EQSTATE_DISABLETXANDRX:
      RILRetailTrace((TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_DISABLETXANDRX)\r\n")));
      g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
      g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
      dwNewModuleState = MODEMSTATE_SIEMENS_AIRPLANE;
      break;

    case RIL_EQSTATE_FULL:
      RILRetailTrace((TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_FULL)\r\n")));
      dwNewModuleState = MODEMSTATE_SIEMENS_POWERON;
      break;
  }

  SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, dwNewState);

  pCmd = new CPowerCmd(dwNewModuleState, pHandle, PwrDeviceUnspecified, PwrDeviceUnspecified, TRUE, FALSE);

  LeaveCriticalSection(&m_csPowerState);

  if (!m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    delete pCmd;
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enable or disable the URCs.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  NewUrcState: The new URC state to be entered.
//  fInit      : Indicating that we're called during the module
//               initialization phase and we have to broadcast some
//               information notifications.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterUrcState(CRilInstanceHandle* pHandle, DWORD dwNewUrcState, BOOL fInit) {
  EnterCriticalSection(&m_csPowerState);

  // URC switching is only allowed when power state and module are on
#ifdef SIEMENS_SMARTFON
  if ((m_PowerState > D2) || !IS_URCSTATE(dwNewUrcState) || (GetEquipmentState() != RIL_EQSTATE_FULL) || (!fInit && !m_fUrcInitialized)) {
#else // SIEMENS_SMARTFON
  if ((m_PowerState != D0) || !IS_URCSTATE(dwNewUrcState) || (GetEquipmentState() != RIL_EQSTATE_FULL) || (!fInit && !m_fUrcInitialized)) {
#endif // SIEMENS_SMARTFON
    RILRetailTrace((TEXT("RilDrv: Invalid call of EnterUrcState()!\r\n")));
    LeaveCriticalSection(&m_csPowerState);
    return FALSE;
  }

  RILRetailTrace((TEXT("RilDrv: EnterUrcState(%s)\r\n"), fInit ? TEXT("init phase") : TEXT("")));

  CPowerCmd* pCmd = new CPowerCmd(dwNewUrcState, pHandle, PwrDeviceUnspecified, PwrDeviceUnspecified, FALSE, fInit);

  LeaveCriticalSection(&m_csPowerState);

  if (!m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    delete pCmd;
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// This is an emergency function to tidy up internal states of the RIL
// driver. It has to be called if the module has lost or is going to loose
// power without the possibility to properly shut it down.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::ForcePowerOff(void) {
BOOL fRet = TRUE;

  SYNCBLOCK(m_csForcePower);

  if (!m_pRilHandle) {
    return FALSE;
  }

  if (!m_fPowerOffForced) {
    SYNCBLOCK(m_csPowerState);

    if (m_dwModemState != MODEMSTATE_SIEMENS_POWEROFF) {
       // Block any further shutdown attempts
       LockPowerState();

      // Turn off module power immediately
       RILRetailTrace((TEXT("RilDrv: Turn off radio directly\r")));    

       RHAFunctionList.pfnRHA_RadioPwrOff();

      m_fPowerOffForced = TRUE;

      UNSYNCBLOCK(m_csForcePower);

      RILRetailTrace((TEXT("RilDrv: Forcing module shutdown!\r\n")));

      // Unlock the Get() function of the response queues
      for (COM_PORT_TYPE i = 0; i < NUMBER_OF_PORTS; i++) {
        g_pRspQ[i]->SetReadLock(FALSE);
      }

      // Block further command handling and any power state changes
      m_pRilHandle->BlockCommandHandling();

      // Try to shutdown the mux
      if (!SendMuxCmd(IOCTL_MPX_POWER_LOSS) && !SendMuxCmd(IOCTL_SIEMENS_MPX_POWER_FAIL)) {
        fRet = FALSE;
      }

      // Now tidy up internal states and send appropriate notifications
      HandleShutdownError();

      // Tidy up possible audio stuff
      RHADeactivateVoicePath(NULL);

      // Save the new equipment state in the registry
      if (m_PowerState == D0) {
        SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, RIL_EQSTATE_MINIMUM);
      }

      // Finally unblock command handling again
      m_pRilHandle->UnblockCommandHandling();

      // Empty possibly queued power commands
      EmptyCmdQueue();
      m_fOngoing = FALSE;
      m_dwNewModemState = m_dwModemState;
      m_dwOldModemState = m_dwModemState;
    }
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Function to be called if a shutdown has properly finished to properly
// tidy up states and abort waiting the timeout thread.
//
// Params:
//  pRes: Pointer to a RILEQUIPMENTSTATE structure filled according to the
//        new equipment state.
//
// Return:
//  TRUE on success, FALSE if anything went wrong.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::ShutdownFinished(LPRILEQUIPMENTSTATE pRes) {
BOOL fUnsolicited = FALSE;

  SYNCBLOCK(m_csPowerState);

  g_iPPLMNBufferPos = PPLMN_BUFFER_NOT_FILLED;
  g_dwSIMLockedState = RIL_LOCKEDSTATE_UNKNOWN;
  ClearGPRSParamCache();

  if (m_dwModemState != MODEMSTATE_SIEMENS_POWEROFF)
  {
		m_pRilHandle->BlockCommandHandling();

		// Store the new equipment state
		m_dwModemState = MODEMSTATE_SIEMENS_POWEROFF;
		m_fUrcInitialized = FALSE;

		if (m_hShutdownThread) {
		// Close handle of finished timeout thread
		CloseHandle(m_hShutdownThread);
		m_hShutdownThread = NULL;
		}
		else
		{
		if (!m_fPowerOffForced) {
		  // We have an unsolicited ^SHUTDOWN -> let the mux know that the module is gone
		  SYNCBLOCK(m_csForcePower);
		  SendMuxCmd(IOCTL_MPX_POWER_LOSS);
		  m_fPowerOffForced = TRUE;
		  fUnsolicited = TRUE;
		}
		}

		// We'll be turning the radio off
		m_pRilHandle->SignalAbortInternalSIMReady();
		g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
		g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
		g_rsiused = 0;
	    if (g_iNrCallInfo > 0) {
	      // When a call is ended by a shutdown, sometimes the ^SLCC URC doesn't show up, so we
	      // broadcast a call state changed notification to allow the MMI to update the display.
	      g_iNrCallInfo = 0;
	      m_pRilHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLSTATECHANGED, NULL, 0);
	    }

	    // Turn off module power
	    if (!m_fPowerOffForced || fUnsolicited) {

/*
#ifdef RIL_MUX_ENABLE
    	    BOOL bRet = TRUE;
    	    DWORD dwBytesRet = 0;
    	  
    	    bRet = DeviceIoControl(g_ComManager.GetPortHandle(RIL_BASE_PORT_TYPE), IOCTL_MUX07_10_SWITCH_RADIO_OFF, 
    	    	                     NULL, 0, NULL, 0, &dwBytesRet, NULL);
    	  
    	    if (!bRet)
    	    {
    	      RILRetailTrace((TEXT("RilDrv: ShutdownFinishThread Failed in DeviceIoControl\r")));    
    	      return -3;
    	    }

	       RILRetailTrace((TEXT("RilDrv: DeviceIoControl to MUX completed\r")));    
#else
*/
           RILRetailTrace((TEXT("RilDrv: Turn off radio directly\r")));    
	       RHAFunctionList.pfnRHA_RadioPwrOff();
//#endif

	    }

    #ifdef SIEMENS_MC45_DSB
        // On Siemens boards iginition is connetcted with DTR
        // We need to clear it explicitly to prevent device emulator from keeping it high
        EscapeCommFunction(g_ComManager.GetPortHandle(DATA_PORT), CLRDTR);
    #endif
    
        // Close all possibly still open port devices
        g_ComManager.CloseAllPortDevices();
    
        // Reset possible RSA connection
        m_pRilHandle->GetRsa()->ResetStates();
    
        m_dwTimeLastOff = GetTickCount();
    
        m_dwInitUrcState = INVALID_MODEM_STATE;
    
        UnlockPowerState();
    
        // Finally unblock command handling again
        m_pRilHandle->UnblockCommandHandling();
    
        RILRetailTrace((TEXT("RilDrv: Module successfully switched off\r\n")));
  }

  if (pRes) {
    FillEquipmentStateStruct(pRes, RIL_EQSTATE_MINIMUM);
    pRes->dwReadyState = 0;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Function to be called if a ^SYSSTART urc has been received.
//
// Params:
//  fFlightMode: Flag indicating if the ^SYSSTART urc belongs to flight mode.
//
// Return:
//  TRUE on success, FALSE if anything went wrong.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SysstartFinished(LPRILEQUIPMENTSTATE pRes, BOOL fFlightMode) {
  SYNCBLOCK(m_csPowerState);

  if (!m_pRilHandle) {
    return FALSE;
  }

  // Abort the waiting timeout thread
  SetEvent(m_hFlightmodeEvent);

  // Store the new equipment state
  m_dwModemState = fFlightMode ? MODEMSTATE_SIEMENS_AIRPLANE : MODEMSTATE_SIEMENS_POWERON;

  if (pRes) {
    FillEquipmentStateStruct(pRes, fFlightMode ? RIL_EQSTATE_DISABLETXANDRX : RIL_EQSTATE_FULL);
    pRes->dwReadyState = 0;
  }

  m_pRilHandle->BlockCommandPriority();

  UnlockPowerState();

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Fill the the given structure according to the supported system power
// states to let the system power manager know what this class is capable of.
// Currently the power states D4, D3, D0 are supported.
// Support bitmasks "pPpc->DeviceDx" and "pPpc->WakeFromDx":
//   0-0-0-D4-D3-D2-D1-D0
//
// Params:
//  pPpc: Pointer to a POWER_CAPABILITIES structure filled according to
//        the supported power states.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::FillPowerCapsStruct(PPOWER_CAPABILITIES pPpc) {
UCHAR  ucPowerMask;
DWORD  dwModemState;
DWORD  dwModemStateD0;

  memset(pPpc, 0, sizeof(POWER_CAPABILITIES));

  dwModemStateD0 = RHAFunctionList.pfnRHA_SystemPowerChange(D4, D0, MODEMSTATE_SIEMENS_POWEROFF, MODEMSTATE_SIEMENS_POWERON, FALSE, TRUE);

  ucPowerMask = 1 << D4;
  for (int i = (int)D4; i >= (int)D0; i--) {
    switch (i) {
      case D0:
      case D1:
      case D2:
        dwModemState = dwModemStateD0;
        break;
      case D3:
        dwModemState = DEFAULT_URCCONFIG;
        break;
      case D4:
      default:
        dwModemState = MODEMSTATE_SIEMENS_POWEROFF;
        break;
    }
    if (i != D0) {
      dwModemState = RHAFunctionList.pfnRHA_SystemPowerChange(D0, (CEDEVICE_POWER_STATE)i, dwModemStateD0, dwModemState, FALSE, TRUE);
    } else {
      dwModemState = dwModemStateD0;
    }
    pPpc->Power[i] = GetMaxPowerConsumption(dwModemState);
    pPpc->Latency[i] = GetMaxLatencyTime(dwModemState, dwModemStateD0);
    pPpc->DeviceDx |= ucPowerMask;
    if ((dwModemState != MODEMSTATE_SIEMENS_POWEROFF) && (dwModemState != MODEMSTATE_SIEMENS_AIRPLANE)) {
      // We can't wake up on external events in power off or airplane mode
      pPpc->WakeFromDx |= ucPowerMask;
    }
    ucPowerMask = ucPowerMask >> 1;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Helper function to fill RILEQUIPMENTSTATE structure and implement
// driver-specific RIL_RADIOSUPPORT_* mapping.
//
// Params:
//  pRes     : Pointer to a RILEQUIPMENTSTATE structure filled according to
//             the new equipment state.
//  dwEqState: The new equipment state used to fill the structure.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::FillEquipmentStateStruct(LPRILEQUIPMENTSTATE pRes, DWORD dwEqState) {
  memset(pRes, 0x00, sizeof(RILEQUIPMENTSTATE));
  pRes->cbSize = sizeof(RILEQUIPMENTSTATE);
  pRes->dwParams = RIL_PARAM_EQUIPMENTSTATE_ALL;
  pRes->dwEqState = dwEqState;
  pRes->dwReadyState = g_dwReadyState;
  if (RIL_EQSTATE_UNKNOWN == dwEqState) {
    pRes->dwRadioSupport = RIL_RADIOSUPPORT_UNKNOWN;
  } else {
    pRes->dwRadioSupport = (dwEqState == RIL_EQSTATE_FULL) ? RIL_RADIOSUPPORT_ON : RIL_RADIOSUPPORT_OFF;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Private class implementation
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Send a command (IOCTL) to the mux driver.
//
// Params:
//  dwCmd: The mux command.
//
// Return:
//  We might have a mux driver not knowing all proprietary IOCTLs. So we
//  simply return always TRUE to keep the code working.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SendMuxCmd(DWORD dwCmd) {

#ifndef DUAL_PORT_SERIAL

#ifdef RIL_MPX1_DRIVER
  // Try to shutdown the mux
  HANDLE hMux = CreateFile(TEXT("MPX1:"), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  if (hMux == INVALID_HANDLE_VALUE) {
    RILRetailTrace((TEXT("RilDrv: Error -Unable to open mux driver\r\n")));
  } else {
    DWORD dwBytesRet;
    if (!DeviceIoControl(hMux, dwCmd, NULL, 0, NULL, 0, &dwBytesRet, NULL)) {
      // Nothing
    }
    CloseHandle(hMux);
  }
#endif
  
#endif // DUAL_PORT_SERIAL

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the maximal possible latency time for a modem state change in
// milliseconds.
//
// Params:
//  StateFrom: The old modem state.
//  StateTo  : The new modem state.
//
// Return:
//  The latency time in milliseconds.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetMaxLatencyTime(DWORD dwStateFrom, DWORD dwStateTo) {
  switch(dwStateFrom) {
    case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
    case MODEMSTATE_SIEMENS_POWEROFF:
      switch (dwStateTo) {
        case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
        case MODEMSTATE_SIEMENS_POWEROFF:
          return 0;
        case MODEMSTATE_SIEMENS_AIRPLANE:
          return 25000;
        case MODEMSTATE_SIEMENS_POWERON:
        default: // MODEMSTATE_SIEMENS_URCCONFIGs
          return 25000;
      }
    case MODEMSTATE_SIEMENS_AIRPLANE:
      switch (dwStateTo) {
        case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_SIEMENS_POWEROFF:
          return 5000;
        case MODEMSTATE_SIEMENS_AIRPLANE:
          return 0;
        case MODEMSTATE_SIEMENS_POWERON:
        default: // MODEMSTATE_SIEMENS_URCCONFIGs
          return 5000;
      }
    case MODEMSTATE_SIEMENS_POWERON:
      switch (dwStateTo) {
        case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_SIEMENS_POWEROFF:
          return 10000;
        case MODEMSTATE_SIEMENS_AIRPLANE:
          return 5000;
        case MODEMSTATE_SIEMENS_POWERON:
          return 0;
        default: // MODEMSTATE_SIEMENS_URCCONFIGs
          return 2500;
      }
    default: // MODEMSTATE_SIEMENS_URCCONFIGs
      switch (dwStateTo) {
        case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_SIEMENS_POWEROFF:
          return 10000;
        case MODEMSTATE_SIEMENS_AIRPLANE:
          return 5000;
        case MODEMSTATE_SIEMENS_POWERON:
          return 2500;
        default: // MODEMSTATE_SIEMENS_URCCONFIGs
          return 0;
      }
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the maximal possible power consumption for a modem state in milliwatts.
//
// Params:
//  ModemState: The modem state to be queried.
//
// Return:
//  The power consumption in milliwatts.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetMaxPowerConsumption(DWORD dwModemState) {
  switch (dwModemState) {
    case MODEMSTATE_SIEMENS_FORCE_POWEROFF:
    case MODEMSTATE_SIEMENS_POWEROFF:
      return 0;
    case MODEMSTATE_SIEMENS_AIRPLANE:
      return 20;
    case MODEMSTATE_SIEMENS_POWERON:
      return 1100;
    default: // MODEMSTATE_SIEMENS_URCCONFIGs
      return 20;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the equipment state from the given modem state.
//
// Params:
//  dwModemState: The modem state we're looking the equipment state for.
//
// Return:
//  The current equipment state.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetEquipmentFromModemState(DWORD dwModemState) {
  switch (dwModemState) {
    case MODEMSTATE_SIEMENS_POWEROFF:
      return RIL_EQSTATE_MINIMUM;
    case MODEMSTATE_SIEMENS_AIRPLANE:
      return RIL_EQSTATE_DISABLETXANDRX;
    default:
      if (IS_URCSTATE(dwModemState)) {
        return RIL_EQSTATE_FULL;
      }
      break;
  }
  return RIL_EQSTATE_UNKNOWN;
}

//////////////////////////////////////////////////////////////////////////////
//
// Generate and broadcast an equipment state changed notification.
//
// Params:
//  pCmd            : Pointer to corresponding power command.
//  dwEquipmentState: The new equipment state.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::GenerateEquipmentNotification(CPowerCmd* pCmd, DWORD dwEquipmentState) {
CNotificationData*  pnd;
RILEQUIPMENTSTATE   res;

  SYNCBLOCK(g_csClosing);

  pnd = new CNotificationData;
  if (!pnd) {
    return FALSE;
  }
  FillEquipmentStateStruct(&res, dwEquipmentState);
  if (dwEquipmentState != RIL_EQSTATE_FULL) {
    res.dwReadyState = 0;
  }
  if (!pnd->InitFromRealBlob(RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED, (void*)&res, res.cbSize)) {
    delete pnd;
    return FALSE;
  }
  GetRilDevice(pCmd ? pCmd->GetHandle() : NULL)->BroadcastNotification(pnd);

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Wait for a possibly running state change to finish and lock further state
// changes.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::WaitAndLockPowerState(void) {
  if (!WaitPowerState()) {
    return FALSE;
  }
  return LockPowerState();
}

//////////////////////////////////////////////////////////////////////////////
//
// Wait for a possibly running state change to finish.
//
// Params:
//  dwEquipmentState: The new equipment state.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::WaitPowerState(void) {
  if (WaitForSingleObject(m_hRadioOnOffMutex, POWER_LOCK_TIMEOUT) != WAIT_OBJECT_0) {
    // Failing to wait for the power mutex indicates a serious problem
    // -> we better turn off the lights
    RILRetailTrace((TEXT("RilDrv: Timeout while waiting for power mutex!\r\n")));
    ForcePowerOff();
    return FALSE;
  }

  EnterCriticalSection(&m_csForcePower);
  if (m_fPowerOffForced) {
    LeaveCriticalSection(&m_csForcePower);
    return FALSE;
  }
  LeaveCriticalSection(&m_csForcePower);

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Empty the power command queue.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::EmptyCmdQueue(void) {
CPowerCmd* pCmd;

  while(SUCCEEDED(m_CmdQueue.Get(pCmd, 0))) {
    delete pCmd;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Empty the power command queue.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::EmptyATCmdQueues(void) {
  for (COM_PORT_TYPE i = 0; i < NUMBER_OF_AVAILABLE_PORTS; i++) {
    while (!g_pCmdQ[i]->FEmpty()) {
      Sleep(10);
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Turn module off completely (D4).
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::TurnOffModule(CPowerCmd* pCmd) {
CRilHandle*  pDevice;
DWORD        dwCmdOpt;
HRESULT      hr = S_OK;

  if (!(pDevice = GetRilDevice(NULL))) {
    return FALSE;
  }

  // Unblock possibly blocked command handling
  pDevice->UnblockCommandHandling();

  dwCmdOpt = CMDOPT_NOOP | CMDOPT_NONE | CMDOPT_IGNORERADIOOFF | CMDOPT_POWER;
  if (!QueueInternalCmdBlocking(COMMAND_PORT, pDevice, NULL, dwCmdOpt, APIID_SETEQUIPMENTSTATE, 0, 0, 0)) {
    HandleShutdownError();
    return FALSE;
  }

  /* Make sure all at cmd had been sent */
  //EmptyATCmdQueues();

  // Block the command handling
  pDevice->BlockCommandHandling();
  

  /* Exit MUX Mode */
  if (!DeviceIoControl(g_ComManager.GetPortHandle(COMMAND_PORT), IOCTL_MUX07_10_EXIT_MUX_MODE, NULL, 0, 
                       NULL, 0, NULL, NULL))
  {
	  RILRetailTrace((TEXT("RilDrv: DeviceIoControl(IOCTL_MUX07_10_EXIT_MUX_MODE) Failed\r\n")));  
  }

  RILRetailTrace((TEXT("RilDrv: DeviceIoControl(IOCTL_MUX07_10_EXIT_MUX_MODE) Completed\r\n")));  
	  
  // Close the used COM ports (mux mode is left automatically with the last virtual port)
  if (!g_ComManager.CloseAllPortDevices()) {
    HandleShutdownError();
    return FALSE;
  }

  SYNCBLOCK(m_csPowerState);
  SYNCBLOCK2(m_csForcePower);
  if (m_fPowerOffForced) {
    return FALSE;
  }
  m_hShutdownThread = CreateThread(NULL, 0, ShutdownFinishThread, this, 0, NULL);
  if (!m_hShutdownThread) {
    HandleShutdownError();
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Turn module on to full operation (D0) from full off mode mode (D4).
//
// Params:
//  pCmd             : Pointer to corresponding power command.
//  fActiveFlightMode: Flag indicating if we have to start in active flight
//                     mode.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::TurnOnModule(CPowerCmd* pCmd, BOOL fActiveFlightMode) {
COM_PORT_TYPE  i;
CRilHandle*    pDevice;
//DWORD          dwMaxOpenAttempts;
//DWORD          dwPortDelay;
//DWORD          j;
DWORD          fInitMicro;
DWORD          dwOpenedPorts;

  if (!(pDevice = GetRilDevice(NULL))) {
    return FALSE;
  }

  // Block the command handling
  pDevice->BlockCommandHandling();

  RILRetailTrace((TEXT("RilDrv: Radio on%s (%dms)\r\n"), fActiveFlightMode ? TEXT(" in airplane mode") : TEXT(""), GetTickCount()));

  TraceDriverInfo();


#ifdef RIL_MUX_ENABLE

  // Open and init the remaining ports
  dwOpenedPorts = 0;
  for (i = 0; i < NUMBER_OF_AVAILABLE_PORTS; i++)
  {
    if (!pDevice->GetComDevice(i)->IsDownstreamPortOpen()) {
      if (g_ComManager.OpenPortDevice(i)) {
        if (!pDevice->GetComDevice(i)->InitComPortForRIL(NULL, NULL)) {
          ForcePowerOff();
          return FALSE;
        }
        dwOpenedPorts++;
      } else {
        // Failed to open port, simply close the port again to block further usage.
        // This might happen because additonal mux ports are not available with older modules.
        RILRetailTrace((TEXT("RilDrv: Failed to open \"%s\", port not available!\r\n"), g_ComManager.GetDebugName(i)));
        g_ComManager.ClosePortDevice(i);
      }
    } else {
      dwOpenedPorts++;
    }
  }
  
  // Check if at least one serial port could be opened
  if (!dwOpenedPorts) {
    ForcePowerOff();
    return FALSE;
  }

  /* Set ModemState and Flight Flag */
  EnterCriticalSection(&m_csPowerState);
  EnterCriticalSection(&m_csForcePower);

  m_dwModemState = fActiveFlightMode ? MODEMSTATE_SIEMENS_AIRPLANE : MODEMSTATE_SIEMENS_POWERON;
  m_fOffToAirplane = fActiveFlightMode;

  LeaveCriticalSection(&m_csForcePower);
  LeaveCriticalSection(&m_csPowerState);

  RILRetailTrace((TEXT("RilDrv: ModemState and Flight Flag Setting Complted!\r\n")));

  // Lock the cmd requeue threads to handle the proper delays
  EnableCmdRequeueWait();

  // Send the pre-init strings in two ports
  if (!g_ComManager.SendPreInitCmds(COMMAND_PORT)) {
    ForcePowerOff();
    return FALSE;
  }

  if (!pDevice->CheckModemType(COMMAND_PORT)) {
    ForcePowerOff();
    return FALSE;
  }

  if (IS_ADI) {
    char  szResponse[128];
    if (!pDevice->ExSendATCmdGetRsp(COMMAND_PORT, "AT^SCFG=\"URC/Datamode/Ringline\",\"006F006E\"\r", szResponse, sizeof(szResponse), 5000, 1)) {
      ForcePowerOff();
      return FALSE;
    }
  }

  if ((g_dwModemType == MODEMTYPE_SIEMENS_MC46) || (g_dwModemType == MODEMTYPE_SIEMENS_MC56)) {
    if (!pDevice->BandHandover(COMMAND_PORT)) {
      ForcePowerOff();
      return FALSE;
    }
  }

  fInitMicro=0;
  
  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitMicroTemp"), &fInitMicro))  {
    if (g_dwModemType == MODEMTYPE_SIEMENS_MC75) {
        fInitMicro = 1;
    }
  }
  
  g_fInitMicroTemp = (fInitMicro==1 ? TRUE : FALSE);
  fInitMicro=0;
  GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitMicroPermanent"), &fInitMicro);

  if (fInitMicro) {
    g_fInitMicroTemp = FALSE;       // When the supply voltage is in permant mode, we have to disable the temp mode.

    if (!pDevice->InitMicrophone(COMMAND_PORT)) {
      ForcePowerOff();
      return FALSE;
    }
  }

  // If there is a more recent set of audio profiles, download them to the modem
  if (pDevice->CheckAudioProfilesVersion(COMMAND_PORT)) {
    if (!pDevice->DownloadAudioProfiles(COMMAND_PORT)) {
      ForcePowerOff();
      return FALSE;
    }
  }

  // Read Audio settings from registry
  GetAudioConfig();

  if (!g_ComManager.SendPreInitCmds(DATA_PORT))
  {
    ForcePowerOff();
    return FALSE;
  }

  // Ensure that the possibly enabled airplane mode is switched off
  if (!EnsureActiveFlightMode(fActiveFlightMode)) {
    RILRetailTrace((TEXT("RilDrv: Error - Unable to initialize the airplane mode\r\n")));
    ForcePowerOff();
    return FALSE;
  }

#endif

  g_iNrCallInfo = -1;  // From here on, there might come incomming calls, so the buffer of call must be reset.
  pDevice->SetIgnoreNextNOCARRIER(FALSE);

  // Re-Initialize the modem
  if (!StartReinitialization(pCmd)) {
    ForcePowerOff();
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start the module initialization sequence.
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::StartReinitialization(CPowerCmd* pCmd) {
DWORD    dwCmdOpt;
HRESULT  hr = S_OK;

  SYNCBLOCK(g_csClosing);

  if (!RHAFunctionList.pfnRHA_IsRadioPwrOn()) {
    return FALSE;
  }

  // Unblock possibly blocked command handling
  GetRilDevice(NULL)->UnblockCommandHandling();

  dwCmdOpt = CMDOPT_NONE | CMDOPT_SETRADIOON | CMDOPT_IGNORERADIOOFF | CMDOPT_REINIT;

  if (pCmd->GetHandle()) {
    if (!QueueCmd(COMMAND_PORT, pCmd->GetHandle(), "AT\r", dwCmdOpt, APIID_SETEQUIPMENTSTATE, NULL, NULL, hr)) {
      RILRetailTrace((TEXT("RilDrv: Error - Unable to queue radio on command\r\n")));
      return FALSE;
    }
  } else {
    if (!QueueInternalCmd(COMMAND_PORT, GetRilDevice(NULL), "AT\r", dwCmdOpt, APIID_SETEQUIPMENTSTATE, 0, 0, 0)) {
      RILRetailTrace((TEXT("RilDrv: Error - Unable to queue radio on command\r\n")));
      return FALSE;
    }
  }

  return SUCCEEDED(hr);
}

//////////////////////////////////////////////////////////////////////////////
//
// Synchronize the port's baud rate setting with the module.
//
// Params:
//  PortType  : The COM port to be used.
//  pRilHandle: Instance of CRilHandle to be used for the operation.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SyncBaudRate(COM_PORT_TYPE PortType, CRilHandle* pDevice) {
DWORD  dwBaudRates[] = BAUDRATES_TO_SCAN;
DWORD  dwNumOfBaudRates = sizeof(dwBaudRates) / sizeof(dwBaudRates[0]);
DWORD  i, k;
DWORD  dwTries;
DWORD  dwErrors;
char   szBaudCmd[32];
char   szResponse[64];
DCB    dcb, dcborg;

  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitTries"), &dwTries)) {
    dwTries = 6;
  }
  if (!dwTries) {
    dwTries = 6;
  }

  // Fetch the required baud rate
  //if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("BaudRate"), &(dwBaudRates[0]))) {
  //  dwBaudRates[0] = CBR_115200;
  //}
  //RILRetailTrace((TEXT("RilDrv: SyncBaudRate() - required baudrate: %d\r\n"), dwBaudRates[0]));
 

  // Construct the command
  dwBaudRates[0] = RIL_FFUART_BAUDRATE;
  sprintf(szBaudCmd, "AT+IPR=%d\r", dwBaudRates[0]);

  // Init the com port for the following baud rate scan
  ClearCommError(g_ComManager.GetPortHandle(PortType), &dwErrors, NULL);
  GetCommState(g_ComManager.GetPortHandle(PortType), &dcborg);
  memcpy(&dcb, &dcborg, sizeof(DCB));
  dcb.fBinary                     = TRUE;
  dcb.fParity                     = FALSE;
  dcb.fOutxCtsFlow                = TRUE;
  dcb.fOutxDsrFlow                = FALSE;
  dcb.fDtrControl                 = DTR_CONTROL_DISABLE;
  dcb.fDsrSensitivity             = FALSE;
  dcb.fTXContinueOnXoff           = TRUE;
  dcb.fOutX                       = FALSE;
  dcb.fInX                        = FALSE;
  dcb.fErrorChar                  = FALSE;
  dcb.fNull                       = FALSE;
  dcb.fRtsControl                 = RTS_CONTROL_ENABLE;
  dcb.fAbortOnError               = FALSE;
  dcb.ByteSize                    = 8;
  dcb.Parity                      = NOPARITY;
  dcb.StopBits                    = ONESTOPBIT;
  EscapeCommFunction(g_ComManager.GetPortHandle(PortType), SETDTR);
  EscapeCommFunction(g_ComManager.GetPortHandle(PortType), SETRTS);
  ClearCommError(g_ComManager.GetPortHandle(PortType), &dwErrors, NULL);
  Sleep(1000);

  // Scan through the list of baud rates and attempt to fix the modem to the required rate
  i = k = 0;
  do {
    dcb.BaudRate = dwBaudRates[i];
    if ((i == 0) || (dcb.BaudRate != dwBaudRates[0])) {
      RILRetailTrace((TEXT("RilDrv: SyncBaudRate() - setting baudrate to: %d\r\n"), dcb.BaudRate));

      // Reset the port
      ClearCommError(g_ComManager.GetPortHandle(PortType), &dwErrors, NULL);
      PurgeComm(g_ComManager.GetPortHandle(PortType), PURGE_RXCLEAR | PURGE_TXCLEAR);

      // Try the new baud rate
      if (SetCommState(g_ComManager.GetPortHandle(PortType), &dcb)) {
        // Send the command to fix the baudrate
        if (pDevice->ExSendATCmdGetRsp(PortType, szBaudCmd, szResponse, sizeof(szResponse), 1000, 0, TRUE)) {
          // If we get an intelligable response we can leave the loop as we have managed to set the baudrate
          if (FindString(0, szResponse, "0\r", sizeof(szResponse), 0)) break;
          if (FindString(0, szResponse, "OK\r\n", sizeof(szResponse), 0)) break;
        } else {
          if (!RHAFunctionList.pfnRHA_IsRadioPwrOn()) {
            RILRetailTrace((TEXT("RilDrv: Abort synchronizing baud rate - Module powered off externally\r\n")));
            return FALSE;
          }
        }
      } else {
        RILRetailTrace((TEXT("RilDrv: SyncBaudRate() - Error applying port settings\r\n")));
      }
    }

    // Prepare next baud rate
    i++;
    if (i >= dwNumOfBaudRates) {
      // If we're at the end of our baud rate list restart the scan
      i = 0;
      k++;
    }
  } while(k < dwTries);

  if (k == dwTries) {
    return FALSE;
  }

  // Restore the original port settings with the new baud rate
  dcborg.BaudRate = dwBaudRates[0];
  SetCommState(g_ComManager.GetPortHandle(PortType), &dcborg);
  PurgeComm(g_ComManager.GetPortHandle(PortType), PURGE_RXCLEAR | PURGE_TXCLEAR);
  ClearCommError(g_ComManager.GetPortHandle(PortType), &dwErrors, NULL);

  // Give system some time for the baud rate switch
  if (dcb.BaudRate != dwBaudRates[0]) {
    Sleep(1000);
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Check if the active flight mode is supported by the connected module.
//
// Return:
//  TRUE if the airplane mode is available, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::ActiveFlightModeAvailable(void) {
  return IS_ADI;
}

//////////////////////////////////////////////////////////////////////////////
//
// Ensure that the active flight mode is deactivated during module start.
//
// Params:
//  fEnter : Flag indicating if the special flight mode shall be entered
//           (TRUE) or left (FALSE).
//
// Return:
//  TRUE on success, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnsureActiveFlightMode(BOOL fEnter) {
CRilHandle*  pDevice;
char         szResponse[256];

  if (!ActiveFlightModeAvailable()) {
    return fEnter ? FALSE : TRUE;
  }

  if (!(pDevice = GetRilDevice(NULL))) {
    return FALSE;
  }

  // Check the OnStart airplane mode setting
  if (!m_pRilHandle->ExSendATCmdGetRsp(COMMAND_PORT, FLIGHTMODE_START_QUERY, szResponse, sizeof(szResponse), 5000, 1)) {
    return FALSE;
  }
  if (!FindString(0, szResponse, "OK\r\n", strlen(szResponse), NULL) && !FindString(0, szResponse, "0\r", strlen(szResponse), NULL)) {
    return FALSE;
  }

  if (!FindString(0, szResponse, FLIGHTMODE_START_RESPONSE(fEnter), strlen(szResponse), NULL)) {
    // Update the OnStart airplane mode setting
    if (!m_pRilHandle->ExSendATCmdGetRsp(COMMAND_PORT, FLIGHTMODE_START(fEnter), szResponse, sizeof(szResponse), 5000, 1)) {
      return FALSE;
    }
  }

  // Check the normal airplane mode setting
  if (!m_pRilHandle->ExSendATCmdGetRsp(COMMAND_PORT, FLIGHTMODE_CMD_QUERY, szResponse, sizeof(szResponse), 5000, 1)) {
    return FALSE;
  }
  if (!FindString(0, szResponse, "OK\r\n", strlen(szResponse), NULL) && !FindString(0, szResponse, "0\r", strlen(szResponse), NULL)) {
    return FALSE;
  }

  if (!FindString(0, szResponse, FLIGHTMODE_CMD_RESPONSE(fEnter), strlen(szResponse), NULL)) {
    // Update the normal airplane mode setting
    if (!m_pRilHandle->ExSendATCmdGetRsp(COMMAND_PORT, FLIGHTMODE_CMD(fEnter), szResponse, sizeof(szResponse), 5000, 1)) {
      return FALSE;
    }
    if (!FindString(0, szResponse, "OK\r\n", strlen(szResponse), NULL) && !FindString(0, szResponse, "0\r", strlen(szResponse), NULL)) {
      return FALSE;
    }

    // The active flight mode has been different before -> we now must wait for the ^SYSSTART-URC
    DWORD  dwStartTime;
    DWORD  dwBytesRead = strlen(szResponse);
    char*  szRcv = szResponse;
    UINT   uiBufLen = sizeof(szResponse) - 1;

    RILRetailTrace((TEXT("RilDrv: Initial flight mode change necessary (%s)\r\n"), fEnter ? TEXT("enter") : TEXT("leave")));

    dwStartTime = GetTickCount();
    while (TRUE) {
      // Check if we have received some data
      if (dwBytesRead > 0) {
        // Scan for ^SYSSTART
        if (FindString(0, szResponse, fEnter ? "^SYSSTART AIRPLANE MODE\r\n" : "^SYSSTART\r\n", strlen(szResponse), NULL)) {
          RILRetailTrace((TEXT("RilDrv: Active flight mode successfully %s\r\n"), fEnter ? TEXT("entered") : TEXT("left")));
          return TRUE;
        }

        szRcv += dwBytesRead;
        uiBufLen -= dwBytesRead;
        if (uiBufLen <= 0) {
          RILRetailTrace((TEXT("RilDrv: Initial flight mode change failed (buffer overflow)\r\n")));
          return FALSE;
        }
      }

      // Wait for some data
      Sleep(100);
      if (!DOWNST_READFILE(g_ComManager.GetPortHandle(COMMAND_PORT), szRcv, uiBufLen, &dwBytesRead)) {
        RILRetailTrace((TEXT("RilDrv: Initial flight mode change failed (port error)\r\n")));
        return FALSE;
      }

      if ((GetTickCount() - dwStartTime) >= FLIGHTMODE_TIMEOUT) {
        RILRetailTrace((TEXT("RilDrv: Initial flight mode change failed (timeout)\r\n")));
        return FALSE;
      }
    }
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch the active module flight mode on or off if it is supported by the module.
//
// Params:
//  pHandle: Pointer to CRilInstanceHandle to be used for the operation.
//  fEnter : Flag indicating if the special flight mode shall be entered
//           (TRUE) or left (FALSE).
//
// Return:
//  TRUE if the module flight mode could be entered, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchActiveFlightMode(BOOL fEnter) {
CRilHandle*  pDevice;
DWORD        dwCmdOpt;

  if (!(pDevice = GetRilDevice(NULL))) {
    return FALSE;
  }

  if (!ActiveFlightModeAvailable()) {
    RILRetailTrace((TEXT("RilDrv: Active flight mode is not supported by the module!\r\n")));
    return FALSE;
  }

  RILRetailTrace((TEXT("RilDrv: %s active flight mode\r\n"), fEnter ? TEXT("Entering") : TEXT("Leaving")));

  // Unblock possibly blocked command handling
  pDevice->UnblockCommandHandling();

  // Block all uncritical commands
  if (!pDevice->BlockCommandPriority(CMDPRI_CRITICAL, fEnter)) {
    RILRetailTrace((TEXT("RilDrv: Failed to block non critical commands!\r\n")));
    return FALSE;
  }

  dwCmdOpt = CMDOPT_POWER;

  // Update the flightmode "OnStart" setting
  if (!QueueInternalCmdBlocking(COMMAND_PORT, pDevice, FLIGHTMODE_START(fEnter), dwCmdOpt, APIID_NONE, 5000, 0, 0)) {
    RILRetailTrace((TEXT("RilDrv: Failed to %s active flight mode start setting\r\n"), fEnter ? TEXT("enable") : TEXT("disable")));
    pDevice->BlockCommandPriority();
    return FALSE;
  }

  {
    SYNCBLOCK(m_csPowerState);
    m_hFlightmodeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!m_hFlightmodeEvent) {
      pDevice->BlockCommandPriority();
      return FALSE;
    }
    HANDLE hThread = CreateThread(NULL, 0, FlightmodeTimeoutThread, this, 0, NULL);
    if (!hThread) {
      CloseHandle(m_hFlightmodeEvent);
      m_hFlightmodeEvent = NULL;
      pDevice->BlockCommandPriority();
      return FALSE;
    }
    CloseHandle(hThread);
  }

  // Now switch the flightmode itself
  if (!QueueInternalCmdBlocking(COMMAND_PORT, pDevice, FLIGHTMODE_CMD(fEnter), dwCmdOpt, APIID_NONE, 5000, 0, 0)) {
    RILRetailTrace((TEXT("RilDrv: Failed to %s active flight mode\r\n"), fEnter ? TEXT("enter") : TEXT("leave")));
    SetEvent(m_hFlightmodeEvent);
    pDevice->BlockCommandPriority();
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Wait for the module to be started by detecting active CTS signal.
//
// Params:
//  PortType  : The COM port to be used.
//  pRilHandle: Instance of CRilHandle to be used for the operation.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::WaitForModuleStart(COM_PORT_TYPE PortType, CRilHandle* pRilHandle) {
DWORD  dwMask;
DWORD  dwStartTime;
DWORD  dwTimeout;

  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitTimeout"), &dwTimeout)) {
    dwTimeout = WAIT_FOR_START_TIMEOUT;
  }
  RILRetailTrace((TEXT("RilDrv: InitTimeout = %d\r\n"), dwTimeout));
      
  // get the initial tick count
  dwStartTime = GetTickCount();

  // Initial delay to give signals some time to settle down
  Sleep(500);

  // Now wait for the CTS signal to become signaled
  while (TRUE) {
    if (!GetCommModemStatus(g_ComManager.GetPortHandle(PortType), &dwMask)) {
      RILRetailTrace((TEXT("RilDrv: Error - Unable to get comm modem status\r\n")));
      return FALSE;
    }
    if (dwMask & MS_CTS_ON) {
      // Active CTS signal detected -> module is on now
      break;
    }
    if ((GetTickCount() - dwStartTime) >= dwTimeout) {
      // We timed out
      RILRetailTrace((TEXT("RilDrv: Error - WaitForModuleStart() timed out!\r\n")));
      return FALSE;
    }
    if (!RHAFunctionList.pfnRHA_IsRadioPwrOn()) {
      // Module powered off externally
      RILRetailTrace((TEXT("RilDrv: Error - Module powered off externally while WaitForModuleStart()!\r\n")));
      return FALSE;
    }
    Sleep(50);
  }

  RILRetailTrace((TEXT("RilDrv: Module started after %d ms\r\n"), GetTickCount() - dwStartTime));

  Sleep(2000);   //Sleep 2 s to wait the modem power on
    
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch on module and block until it has started.
//
// Params:
//  PortType         : The COM port to be used.
//  pRilHandle       : Instance of CRilHandle to be used for the operation.
//  fActiveFlightMode: Flag indicating if we have to start in active flight
//                     mode.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchModuleOn(COM_PORT_TYPE PortType, CRilHandle* pRilHandle, BOOL fActiveFlightMode) {
  BOOL bRet = TRUE;
  DWORD dwBytesRet = 0;
  
  EnterCriticalSection(&m_csPowerState);
  EnterCriticalSection(&m_csForcePower);

  // Call the customer function to switch on the radio
#ifdef RIL_MUX_ENABLE  
  //The device had already been opened
  //bRet = DeviceIoControl(g_ComManager.GetPortHandle(PortType), IOCTL_MUX07_10_SWITCH_RADIO_ON, NULL, 0, NULL, 0, &dwBytesRet, NULL);
  //if (!bRet) return bRet;
   	
#else
  bRet = RHAFunctionList.pfnRHA_RadioPwrOn();
  if (!bRet) return bRet;
#endif


#ifdef SIEMENS_MC45_DSB
  // On Siemens boards iginition is connetcted with DTR
  EscapeCommFunction(g_ComManager.GetPortHandle(PortType), SETDTR);
#endif

  // Signal the radio is now on
  m_dwModemState = fActiveFlightMode ? MODEMSTATE_SIEMENS_AIRPLANE : MODEMSTATE_SIEMENS_POWERON;
  m_fOffToAirplane = fActiveFlightMode;

  LeaveCriticalSection(&m_csForcePower);
  LeaveCriticalSection(&m_csPowerState);

#ifndef RIL_MUX_ENABLE
  bRet = WaitForModuleStart(PortType, pRilHandle);
#endif

  // now wait for the module to start
  return bRet;
}


//////////////////////////////////////////////////////////////////////////////
//
// Increase or decrease the systems unattended mode counter.
//
// Params:
//  fOnOff: Flag indicating if the unattended mode shall be entered (counter
//          increased) or left (counter decreased).
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::SwitchIdleTimerReset(BOOL fOnOff) {
#ifdef RIL_ENABLE_UNATTENDED_HANDLING
#ifdef RIL_ENABLE_POWER_HANDLING
  SYNCBLOCK(m_csUnattended);
  if (m_hIdleResetLeaveEvent) {
    if (fOnOff) {
      if (!m_fIdleTimerReset) {
        // Start the thread which resets the system idle timer
        ResetEvent(m_hIdleResetLeaveEvent);
        if (!CloseHandle(CreateThread(NULL, 0, IdleTimerResetThread, this, 0, NULL))) {
          RILRetailTrace((TEXT("RilDrv: Failed to create idle timer reset thread!\r\n")));
          return;
        }
        m_fIdleTimerReset = TRUE;
        RILRetailTrace((TEXT("RilDrv: Started cyclic system idle timer reset\r\n")));
      }
    } else {
      if (m_fIdleTimerReset) {
        // Stop the thread which resets the system idle timer
        SetEvent(m_hIdleResetLeaveEvent);
        RILRetailTrace((TEXT("RilDrv: Stopped cyclic system idle timer reset\r\n")));
        m_fIdleTimerReset = FALSE;
      }
    }
  }
#endif // RIL_ENABLE_POWER_HANDLING
#endif // RIL_ENABLE_UNATTENDED_HANDLING
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread to reset the system idle timer cyclicly while we requested the
// unattended mode.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::IdleTimerResetThread(LPVOID lpParameter) {
CPowerManager* pHandle = (CPowerManager*)lpParameter;

  if (pHandle) {
    if (pHandle->m_hIdleResetLeaveEvent) {
      while (WaitForSingleObject(pHandle->m_hIdleResetLeaveEvent, IDLE_TIMER_RESET_CYCLE) == WAIT_TIMEOUT) {
        SystemIdleTimerReset();
      }
    }
  }
  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Increase or decrease the systems unattended mode counter.
//
// Params:
//  fOnOff: Flag indicating if the unattended mode shall be entered (counter
//          increased) or left (counter decreased).
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::SwitchUnattendedMode(BOOL fOnOff) {
#ifdef RIL_ENABLE_UNATTENDED_HANDLING
#ifdef RIL_ENABLE_POWER_HANDLING
  SYNCBLOCK(m_csUnattended);
  if (fOnOff) {
    if (!m_fUnattendedMode) {
      if (!PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE)) {
        RILRetailTrace((TEXT("RilDrv: Unattended-Mode add-request failed!\r\n")));
        return;
      }
      m_fUnattendedMode = TRUE;
      RILRetailTrace((TEXT("RilDrv: Unattended-Mode request added\r\n")));
    }
  } else {
    if (m_fUnattendedMode) {
      if (!PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE)) {
        RILRetailTrace((TEXT("RilDrv: Unattended-Mode remove-request failed!\r\n")));
        return;
      }
      m_fUnattendedMode = FALSE;
      RILRetailTrace((TEXT("RilDrv: Unattended-Mode request removed\r\n")));
    }
  }
#endif // RIL_ENABLE_POWER_HANDLING
#endif // RIL_ENABLE_UNATTENDED_HANDLING
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing callback for SwitchUscState()
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CPowerManager::ParseGetRegStatusAll(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
CPowerManager*  pDevice = (CPowerManager*)pParam;
UINT            nValue;
DWORD*          pdwRegStatus = NULL;
UINT            nRSSI, nBER;
HRESULT         hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // Parse "<prefix>+CREG: <mode>,<status><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "+CREG: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp))          {
    hr = E_FAIL;
    goto Error;
  }

  // There may be additional information, but we ignore them.
  if (MatchStringBeginning(szRsp, ",\"", szRsp))
  {
      ParseHexUInt(szRsp, TRUE, pDevice->m_nLAC, szRsp);
      MatchStringBeginning(szRsp, "\",\"", szRsp);
      ParseHexUInt(szRsp, TRUE, pDevice->m_nCI, szRsp);
      MatchStringBeginning(szRsp, "\"", szRsp);
  }

  if (!ParseRspPostfix(szRsp, szRsp))
  {
      hr = E_FAIL;
      goto Error;
  }

  if (NUM_REGSTATS > nValue) {
    g_dwRegStatus = g_rgdwRegStats[nValue];
  } else {
    g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
  }

  // Parse "<prefix>+CGREG: <mode>,<status><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "+CGREG: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)           ||
      !MatchStringBeginning(szRsp, ",", szRsp)         ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  if (NUM_REGSTATS > nValue) {
    g_dwGPRSRegStatus = g_rgdwRegStats[nValue];
  } else {
    g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
  }
  if (g_dwModemType == MODEMTYPE_SIEMENS_MC75 && g_dwModemVersion >= 1900 && g_dwModemVersion <=2001)
  {
      // MC75: the +CGREG: URC shows on some network "Home" while roaming. The +CREG URC
      // shows the correct value.
      if (g_dwGPRSRegStatus == RIL_REGSTAT_HOME && g_dwRegStatus == RIL_REGSTAT_ROAMING)
      {
          g_dwGPRSRegStatus = RIL_REGSTAT_ROAMING;
      }
  }

  // Parse "<prefix>+CSQ: <rssi>,<ber><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                             ||
      !MatchStringBeginning(szRsp, "+CSQ: ", szRsp)             ||
      !ParseUIntAndVerifyAbove(szRsp, TRUE, 100, nRSSI, szRsp)  ||
      !MatchStringBeginning(szRsp, ",", szRsp)                  ||
      !ParseUInt(szRsp, TRUE, nBER, szRsp)                      ||
      !ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  g_nRSSI = nRSSI;
  g_nBER = nBER;

  if (nRSSI == 99) {
    g_iLastRSSI = nRSSI;
  } else {
    g_iLastRSSI = (2 * nRSSI) / 15;
  }
  g_iLastSignal = nBER;

Error:
  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing callback for "AT+CSMS?;+CNMI?" request SwitchUscState()
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CPowerManager::ParseGetSMSPhase(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT            nValue;
UINT            nPhase;
UINT            nMode;
CPowerManager*  pDevice = (CPowerManager*)pParam;
DWORD*          pdwRegStatus = NULL;
HRESULT         hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // Parse "<prefix>+CSMS: <phase>,<p1>,<p2>,<p3><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "+CSMS: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nPhase, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }
  // Parse "<prefix>+CNMI: <mode>,<mt>,<bm>,<ds>,<bfr><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "+CNMI: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nMode, szRsp)           ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  pDevice->m_nSMSPhase = nPhase;
  pDevice->m_nCNMIMode = nMode;

Error:
  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch the module to the given URC state.
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchUrcState(CPowerCmd* pCmd) {
CRilHandle*  pDevice;
const char*  szATCmd = NULL;
const char*  szATCFUNCCmd = NULL;
DWORD        dwNewUrcState;
char szCmd[MAX_ATCMD_LEN];

  if (!IS_URCSTATE(pCmd->GetCmd())) {
    return FALSE;
  }

  if (!(pDevice = GetRilDevice(NULL))) {
    return FALSE;
  }

  // An URC switch before being initialized makes no sense.
  if (!m_fUrcInitialized && !pCmd->IsUrcInit()) {
    m_dwInitUrcState = pCmd->GetCmd();
    return FALSE;
  }

  // Check if we have to overwrite the given int URC state from a previous power state call
  dwNewUrcState = pCmd->GetCmd();
  if (pCmd->IsUrcInit() && IS_URCSTATE(m_dwInitUrcState)) {
    dwNewUrcState = m_dwInitUrcState;
    m_dwInitUrcState = INVALID_MODEM_STATE;
    RILRetailTrace((TEXT("RilDrv: Overwritten given init URC state from former power command\r\n")));
  }

  if (m_fUrcInitialized) {
    // We don't support direct URCCONFIG switches!
    if (IS_URCCONFIG(m_dwModemState) && IS_URCCONFIG(dwNewUrcState) && (m_dwModemState != dwNewUrcState)) {
      // So we must enable the URCs before switching to the new URCCONFIG...
      if (!SwitchUrcState(&CPowerCmd(MODEMSTATE_SIEMENS_POWERON, pCmd->GetHandle(), pCmd->GetNewPowerState(), pCmd->GetOldPowerState(), pCmd->IsEquipmentStateCmd(), pCmd->IsUrcInit()))) {
        return FALSE;
      }
    }
    // Now check if we are already in the requested URC state
    if (m_dwModemState == dwNewUrcState) {
      // Nothing more to do
      return TRUE;
    }
  }

  // Unblock possibly blocked command handling
  pDevice->UnblockCommandHandling();

  // Now switch to the requested URC state
  if (dwNewUrcState == MODEMSTATE_SIEMENS_POWERON) {
    CNotificationData *pnd = NULL;
    BOOL fCheckMissedSMS = TRUE;

    RILRetailTrace((TEXT("RilRrv: SwitchUrcState(MODEMSTATE_SIEMENS_POWERON)\r\n")));

    // For Wake up from CFUN = 0, it needn't CFUN=1 to enter full funciton, it automatic enter 1 after wake up.
    
    szATCmd = "AT+CREG=2;+CGREG=1;"CMD_INDICATOR_CTRL"\r";

    // Enable URCs
    if (!QueueInternalCmd(URC_PORT, pDevice, szATCmd, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY)) {
      return FALSE;
    }
    // Fetch the registration status (+CREG and +CGREG) and signal strenght (+CSQ)
    m_nLAC = 0;
    m_nCI = 0;


    if (!QueueInternalCmdBlocking(URC_PORT, pDevice, "AT+CREG?;+CGREG?;+CSQ\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetRegStatusAll, NULL, this)) {
      return FALSE;
    }
    RILRetailTrace((TEXT("RilRrv: SwitchUrcState(AT+CSQ) Completed\r\n")));

    // We generate a RIL_NOTIFY_REGSTATUSCHANGED notification, when the AT+CREG status changed.
    // In case we are roaming, we send this notification in any case, to force the OS to check,
    // if the roaming network changed.
    if ((m_dwRegStatusCache != g_dwRegStatus) || (m_dwRegStatusCache == RIL_REGSTAT_ROAMING) || pCmd->IsUrcInit()) {
      // Notify the OS
      pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_REGSTATUSCHANGED, g_dwRegStatus);
    }
    if ((m_dwGPRSRegStatusCache != g_dwGPRSRegStatus) || pCmd->IsUrcInit()) {
      pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_GPRSREGSTATUSCHANGED, g_dwGPRSRegStatus);
    }
    Sleep(200);

#ifndef RIL_NO_CREG_LOCATION_UPDATES
    if (m_nLAC && m_nCI) {
      CNotificationData *pnd2 = NULL;
      RILLOCATIONINFO sLI;

      sLI.cbSize = sizeof(RILLOCATIONINFO);
      sLI.dwLocationAreaCode = m_nLAC;
      sLI.dwCellID = m_nCI;

      pnd2 = new CNotificationData;
      if (pnd2) {
        if (!pnd2->InitFromRealBlob(RIL_NOTIFY_LOCATIONUPDATE, &sLI, sizeof(RILLOCATIONINFO))) {
          delete pnd2;
          pnd = NULL;
        }
      }
      pDevice->BroadcastNotification(pnd2);
    }
#endif
#ifdef RIL_USE_CSQ_NOTIFICATIONS
    RILSIGNALQUALITY rsq;
    FillRSQStruct(&rsq);
    pnd = new CNotificationData;
    if (pnd) {
      if (!pnd->InitFromRealBlob(RIL_NOTIFY_SIGNALQUALITY, &rsq, sizeof(RILSIGNALQUALITY))) {
        delete pnd;
        pnd = NULL;
      }
    }
    pDevice->BroadcastNotification(pnd);

    // We already got the +CIEV URC? Resend the information.
    if (g_bCINDIsActive) {
      CreateThread(NULL, 0, ReSendSignalThreadProc, pDevice, 0, 0);
    }
#endif

    m_nSMSPhase = 1;     // Default: SMS Phase 2+
    m_nCNMIMode = 0;    // Default: CNMI not active
    if (!QueueInternalCmdBlocking(URC_PORT, pDevice, "AT+CSMS?;+CNMI?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetSMSPhase, NULL, this)) {
      return FALSE;
    }

    // If CNMI is already active, we don't need to check for missed SMS, since we have received the URC. Otherwise
    // we might accidently notify the OS twice about the same SMS.
    // Only during the init phase we have to check alway, if there are any missed SMS, which might came in during
    // the initialization of the radio.
    if (!pCmd->IsUrcInit() && (m_nCNMIMode > 0)) {
      fCheckMissedSMS = FALSE;
    }

    if (m_nSMSPhase == 0) {
      QueueInternalCmd(URC_PORT, pDevice, SMS_PHASE2_CNMI, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
    } else {
      QueueInternalCmd(URC_PORT, pDevice, SMS_PHASE2PLUS_CNMI, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
    }

    if (g_fReceiveCellBroadCast)
   	{
	   	//(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCB=%u,\"%s\",\"%s\"\r", g_fReceiveCellBroadCast, g_szReceiveCellBroadCastChannels, g_szReceiveCellBroadCastDCS);
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCB=%u,\"%s\",\"%s\"\r", 0, g_szReceiveCellBroadCastChannels, g_szReceiveCellBroadCastDCS);	   	
		QueueInternalCmd(URC_PORT, pDevice, szCmd, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
	}
	else
	{
	   	//(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCB=%u,\"%s\",\"%s\"\r", g_fReceiveCellBroadCast, g_szReceiveCellBroadCastChannels, g_szReceiveCellBroadCastDCS);
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCB=%u\r", 0);	   	
		QueueInternalCmd(URC_PORT, pDevice, szCmd, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
	}
    		

    if (fCheckMissedSMS) {
      QueueInternalCmd(COMMAND_PORT, pDevice, "AT^SMGL=0\r", CMDOPT_URC, APIID_QUERYUNREADSMS, 0, 0, 0, ParseSMSListAndSendAck, NULL, pDevice);
    }

    CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)pDevice, 0, 0);

  } else {
  
    switch (dwNewUrcState) {
      case MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS_REG:
        // During suspend mode we have to switch back to SMS phase 2, because not all devices are
        // able to wake up fast enough to acknowledge an incomming SMS in time.
        RILRetailTrace((TEXT("RilRrv: SwitchUrcState(MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS_REG)\r\n")));
        szATCmd = "AT+CIND=0,0,0,0,0,0,0,0,0;+CNMI=2,1,2,2,1\r";
        break;
      case MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS:
        // See comment above about SMS.
        RILRetailTrace((TEXT("RilRrv: SwitchUrcState(MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS)\r\n")));
        szATCmd = "AT+CREG=0;+CGREG=0;+CIND=0,0,0,0,0,0,0,0,0;+CNMI=2,1,2,2,1\r";
        break;
      case MODEMSTATE_SIEMENS_URCCONFIG_CALL:
        // Although all URCs are disabled, we have to enable the "SIM full" notification, because
        // outherwise we could lose SMS.
        RILRetailTrace((TEXT("RilRrv: SwitchUrcState(MODEMSTATE_SIEMENS_URCCONFIG_CALL)\r\n")));
        szATCmd = "AT+CREG=0;+CGREG=0;+CIND=0,0,0,0,0,0,0,1,0;+CSCB=0,\"\",\"\";+CNMI=0,0,0,0\r";
        break;
      default:
        return FALSE;
    }

    if (!QueueInternalCmdBlocking(URC_PORT, pDevice, szATCmd, CMDOPT_URC, APIID_NONE, 5000, 2, 1000)) {
      return FALSE;
    }

#ifdef RIL_MUX_ENABLE


#else
    /* Put modem into sleep mode before system go to sleep */
    szATCFUNCCmd = "AT+CFUN=0;\r";
    
    if (!QueueInternalCmdBlocking(URC_PORT, pDevice, szATCFUNCCmd, CMDOPT_URC, APIID_NONE, 5000, 2, 1000)) {
      return FALSE;
    }
#endif

    // Save the last status
    m_dwRegStatusCache = g_dwRegStatus;
    m_dwGPRSRegStatusCache = g_dwGPRSRegStatus;
    // No more CIND indications, we have to use AT+CSQ to get the signal quality.
    g_bCINDIsActive = FALSE;
  }

  m_dwModemState = dwNewUrcState;
  m_fUrcInitialized = TRUE;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Tidy up internal states after any shutdown error.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::HandleShutdownError(void) {
  RILEQUIPMENTSTATE   res;
  CNotificationData*  pnd;

  SYNCBLOCK(m_csPowerState);

  RILRetailTrace((TEXT("RilDrv: Forcing radio off!\r\n")));

  // Tidy up internal states
  ShutdownFinished(&res);

#ifdef SIEMENS_MC45_DSB
    // On Siemens boards iginition is connetcted with DTR
    // We need to clear it explicitly to prevent device emulator from keeping it high
    if (g_ComManager.OpenBasePort()) {
      EscapeCommFunction(g_ComManager.GetPortHandle(DATA_PORT), CLRDTR);
      g_ComManager.CloseBasePort();
    }
#endif

  // Signal RIL is no longer ready
  m_pRilHandle->StopReadyStateQuery();
  m_pRilHandle->SendReadyStateNotification(RIL_READYSTATE_NONE, FALSE);

  UpdateSIMState(RIL_E_RADIOOFF);

  // Notify the OS of the change in radio power state
  pnd = new CNotificationData;
  if (pnd && pnd->InitFromRealBlob(RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED, &res, res.cbSize)) {
    m_pRilHandle->BroadcastNotification(pnd);
    pnd = NULL;
  }
  delete pnd;
}

//////////////////////////////////////////////////////////////////////////////
//
// Finish a shutdown by sending "AT^SMSO" and waiting for "^SHUTDOWN".
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::ShutdownFinishThread(LPVOID lpParameter) {
CPowerManager*  pHandle = (CPowerManager*)lpParameter;

	DWORD           dwStartTime;
	DWORD           dwBytesRead;
	char*           szRcv;
	UINT            uiBufLen;
	char            szResponse[256];

   // Check our instance handle
   if (!pHandle) {
     return -1;
   }

    if (!g_ComManager.OpenBasePort()) {
     pHandle->HandleShutdownError();
     return -2;
   }

   RILRetailTrace((TEXT("RilDrv: ShutdownFinishThread Open Base Port Successfully\r\n")));

  // Send the power off command
  if (!pHandle->m_pRilHandle->ExSendATCmdGetRsp(RIL_BASE_PORT_TYPE, "AT^SMSO\r", szResponse, sizeof(szResponse), g_TimeoutAPIDefault, 3)) {
    pHandle->HandleShutdownError();
    return -3;
  }

  // Now wait for the "^SHUTDOWN" urc
  dwStartTime;
  dwBytesRead = strlen(szResponse);
  szRcv = szResponse;
  uiBufLen = sizeof(szResponse) - 1;

  dwStartTime = GetTickCount();
  while (TRUE) {
    // Check if we have received some data
    if (dwBytesRead > 0) {
      if (FindString(0, szResponse, "^SHUTDOWN\r\n", strlen(szResponse), NULL)) {
        RILRetailTrace((TEXT("RilDrv: Received \"^SHUTDOWN\" urc (Base Port)\r\n")));
        pHandle->ShutdownFinished(NULL);
        pHandle->GenerateEquipmentNotification(NULL, pHandle->GetEquipmentState());
        break;
      }

      szRcv += dwBytesRead;
      uiBufLen -= dwBytesRead;
      if (uiBufLen <= 0) {
        pHandle->HandleShutdownError();
        return -4;
      }
    }

    // Wait for some data
    Sleep(100);
    if (!DOWNST_READFILE(g_ComManager.GetPortHandle(RIL_BASE_PORT_TYPE), szRcv, uiBufLen, &dwBytesRead)) {
      pHandle->HandleShutdownError();
      return -5;
    }

    if ((GetTickCount() - dwStartTime) >= SHUTDOWN_TIMEOUT) {
      RILRetailTrace((TEXT("RilDrv: Timeout while waiting for shutdown!\r\n")));
      pHandle->HandleShutdownError();
      return -6;
    }

    SYNCBLOCK(pHandle->m_csPowerState);
    SYNCBLOCK2(pHandle->m_csForcePower);

    if (!pHandle->m_hShutdownThread) {
      // We have been closed externally
      return -7;
    }	

  }
//#endif

  // Close the used COM ports (mux mode is left automatically with the last virtual port)
  if (!g_ComManager.CloseBasePort()) {
    pHandle->HandleShutdownError();
    return -8;
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Timeout thread to handle problems with the active flight mode.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//        back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::FlightmodeTimeoutThread(LPVOID lpParameter) {
CPowerManager*  pHandle = (CPowerManager*)lpParameter;
HANDLE          hEvent;
DWORD           dwEvent;

  // Check our instance handle
  if (!pHandle) {
    return -1;
  } else {
    EnterCriticalSection(&(pHandle->m_csPowerState));
    hEvent = pHandle->m_hFlightmodeEvent;
    LeaveCriticalSection(&(pHandle->m_csPowerState));
  }

  // Wait for the flightmode to arrive
  if (hEvent) {
    dwEvent = WaitForSingleObject(hEvent, FLIGHTMODE_TIMEOUT);
    EnterCriticalSection(&(pHandle->m_csPowerState));
    CloseHandle(hEvent);
    pHandle->m_hFlightmodeEvent = NULL;
    LeaveCriticalSection(&(pHandle->m_csPowerState));
    // If we haven't received ^SYSSTART within the timeout -> switch module off
    if (dwEvent == WAIT_TIMEOUT) {
      RILRetailTrace((TEXT("RilDrv: Timeout while waiting for active flight mode -> switching module off!\r\n")));
      pHandle->m_pRilHandle->BlockCommandPriority();
      if (!pHandle->TurnOffModule(NULL)) {
        // Something went utterly wrong -> force everything off
        pHandle->ForcePowerOff();
      }
    }
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::InitIPM() 
{
    IPM_STATUS_T enIPMStatus = IPM_STATUS_SUCCESS;
    DWORD dwInitProcState = IPM_PROCESSOR_D0_RDY;
//        IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D1_RDY | IPM_PROCESSOR_D2_RDY;

    m_IPMClientID = INVALID_CLIENT_ID;

    enIPMStatus = IPM_Register(TEXT("RIL1:"), &m_IPMClientID, 3000);
    
    if ((IPM_STATUS_SUCCESS != enIPMStatus) && (IPM_STATUS_IPM_DISABLED != enIPMStatus))
    {
        RILRetailTrace((TEXT("RILDrv: IPM IPM_Register Error = %d .\n"), enIPMStatus));
        m_IPMClientID = INVALID_CLIENT_ID;        
        return FALSE;
    }
    else if (IPM_STATUS_IPM_DISABLED == enIPMStatus)
    {
        RILRetailTrace((TEXT("RILDrv: IPM is disabled.\n")));
        return TRUE;
    }

    RILRetailTrace((TEXT("RILDrv: IPM_Register Successfully. ID = %d .\n"), m_IPMClientID));

    enIPMStatus = IPM_NotifyReadyForProcState(m_IPMClientID, dwInitProcState , 3000);
    
    if (IPM_STATUS_SUCCESS != enIPMStatus)
    {
        RILRetailTrace((TEXT("RILDrv: IPM_NotifyReadyForProcState Failed!\n")));  
        return FALSE;
    }
    if ( IPM_SetMinOp(m_IPMClientID,IPM_OP_624MHZ, 3000) != IPM_STATUS_SUCCESS)
        RETAILMSG(1, (_T("USBOTG: IPM_SetMinOp failed\r\n")));
    return TRUE;
}



//////////////////////////////////////////////////////////////////////////////
//
// Handler for the power command queue.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::CmdQueueHandler(void) {
CPowerCmd*   pCmd;
DWORD        dwLastEquipmentState;
BOOL         fSwitchedOn;
BOOL         fBlock;
BOOL         fUnblock;
BOOL         fEmpty;
BOOL         fClrRTS;
BOOL         fRTSCleared = FALSE;

  while (TRUE) {
    if (FAILED(m_CmdQueue.Get(pCmd, INFINITE)) || !pCmd) {
      RILRetailTrace((TEXT("RilDrv: Leaving power command queue\r\n")));
      return 0;
    }

    RILRetailTrace((TEXT("RilDrv: Handling %s command \"%s\"\r\n"), pCmd->IsPowerCmd() ? TEXT("power") : (pCmd->IsEquipmentStateCmd() ? TEXT("equipment state") : TEXT("urc")), GetCmdName(pCmd->GetCmd())));

    if (pCmd->GetCmd() == MODEMSTATE_SIEMENS_FORCE_POWEROFF) {
      // Empty command queues
      EmptyATCmdQueues();
      // Block further commands on power states D2 and below, unregister unattended mode
      if ((pCmd->GetNewPowerState() >= D2) && (pCmd->GetOldPowerState() <= D1)) {
        GetRilDevice(NULL)->BlockCommandHandling();
        SwitchUnattendedMode(FALSE);
      }
      // Command has been executed before, just delete it
      delete pCmd;
      continue;
    }

    EnterCriticalSection(&m_csPowerState);

    if (!pCmd->IsPowerCmd() && pCmd->IsUrcCmd()) {
      if (m_PowerState != D0) {
        // URC commands are only allowed in power state D0
        RILRetailTrace((TEXT("RilDrv: Removing invalid URC command from queue\r\n")));
        delete pCmd;
        LeaveCriticalSection(&m_csPowerState);
        continue;
      }
      if (!pCmd->IsUrcInit() && !m_fUrcInitialized) {
        // We have an external URC cmd before URCs are initialized
        RILRetailTrace((TEXT("RilDrv: Removing invalid early urc switch\r\n")));
        delete pCmd;
        LeaveCriticalSection(&m_csPowerState);
        continue;
      }
      if (pCmd->IsUrcInit() && (m_dwModemState == MODEMSTATE_SIEMENS_POWEROFF)) {
        // We've been switched off during the init phase
        RILRetailTrace((TEXT("RilDrv: Removing late urc initialization\r\n")));
        delete pCmd;
        LeaveCriticalSection(&m_csPowerState);
        continue;
      }
    }

    // Save the new equipment state in the registry
    if (m_PowerState == D0) {
      switch(pCmd->GetCmd()) {
        case MODEMSTATE_SIEMENS_POWEROFF:
          dwLastEquipmentState = RIL_EQSTATE_MINIMUM;
          break;
        case MODEMSTATE_SIEMENS_AIRPLANE:
          dwLastEquipmentState = RIL_EQSTATE_DISABLETXANDRX;
          break;
        default:
          dwLastEquipmentState = RIL_EQSTATE_FULL;
          break;
      }
      SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, dwLastEquipmentState);
    }

    m_fOngoing = TRUE;
    m_dwNewModemState = pCmd->GetCmd();
    m_dwOldModemState = m_dwModemState;
    dwLastEquipmentState = GetEquipmentState();
    if (pCmd->GetCmd() != MODEMSTATE_SIEMENS_POWEROFF) {
      m_fPowerOffForced = FALSE;
    }

    LeaveCriticalSection(&m_csPowerState);

    // Start the system idle timer reset
    SwitchIdleTimerReset(TRUE);

    // Lock the on/off mutex
    WaitAndLockPowerState();

    // Enable hardware RTS handshake again
    if (fRTSCleared) {
      DWORD  dwSleep;
      if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitAfterResume"), &dwSleep)) {
        Sleep(dwSleep);
      }
      fRTSCleared = FALSE;
      SendMuxCmd(IOCTL_MPX_SET_HW_RTS);
    }

#ifdef RIL_ENABLE_RING_ON_INCOMMING_DATA
    if (pCmd->IsPowerCmd() && IS_URCSTATE(m_dwModemState) && (pCmd->GetNewPowerState() <= D2)) {
      for (COM_PORT_TYPE i = 0; i < NUMBER_OF_AVAILABLE_PORTS; i++) {
        CComHandle* pComDevice = GetRilDevice(NULL)->GetComDevice(i);
        if (pComDevice) {
          DCB dcb;

          if (pComDevice->VirtGetCommState(&dcb)) {
            dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
            pComDevice->VirtSetCommState(&dcb);
          }
        }
      }
    }
#endif

    // Set the desired new module state
    fSwitchedOn = FALSE;
    switch (pCmd->GetCmd()) {
      case MODEMSTATE_SIEMENS_POWEROFF:
        switch (m_dwModemState) {
          case MODEMSTATE_SIEMENS_POWEROFF:
            // Nothing to do
            UnlockPowerState();
            break;
          case MODEMSTATE_SIEMENS_POWERON:
          case MODEMSTATE_SIEMENS_AIRPLANE:
          default: // MODEMSTATE_SIEMENS_URCCONFIGs
            if (!TurnOffModule(pCmd)) {
              UnlockPowerState();
            }
            break;
        }
        break;

      case MODEMSTATE_SIEMENS_AIRPLANE:
        switch (m_dwModemState) {
          case MODEMSTATE_SIEMENS_POWEROFF:
            if (!ActiveFlightModeAvailable()) {
              // If there is no airplane mode available the module must stay off.
              // That happens also if the module type is still unknown because it
              // had never been switched on before!
              UnlockPowerState();
            } else {
              // Otherwise we try to start the module directly in airplane mode
              if (!TurnOnModule(pCmd, TRUE)) {
                UnlockPowerState();
              }
              fSwitchedOn = TRUE;
            }
            break;
          case MODEMSTATE_SIEMENS_AIRPLANE:
            // Nothing to do
            UnlockPowerState();
            break;
          case MODEMSTATE_SIEMENS_POWERON:
          default: // MODEMSTATE_SIEMENS_URCCONFIGs
            if (IS_URCCONFIG(m_dwModemState)) {
              // First enable URCs again for later state changes
              SwitchUrcState(&CPowerCmd(MODEMSTATE_SIEMENS_POWERON, NULL, PwrDeviceUnspecified, PwrDeviceUnspecified, TRUE, FALSE));
            }
            if (!SwitchActiveFlightMode(TRUE)) {
              // Failed to enter airplane mode -> switch module off
              if (!TurnOffModule(pCmd)) {
                UnlockPowerState();
              }
            }
            break;
        }
        break;

      case MODEMSTATE_SIEMENS_POWERON:
        switch (m_dwModemState) {
          case MODEMSTATE_SIEMENS_POWEROFF:
            if (!TurnOnModule(pCmd, FALSE)) {
              UnlockPowerState();
            }
            fSwitchedOn = TRUE;
            break;
          case MODEMSTATE_SIEMENS_AIRPLANE:
            if (!SwitchActiveFlightMode(FALSE)) {
              UnlockPowerState();
            }
            if (m_fOffToAirplane) {
              // If we had been switched form off to airplane mode we have to repeat the initialization
              WaitAndLockPowerState();
              if (!StartReinitialization(pCmd)) {
                UnlockPowerState();
              }
              m_fOffToAirplane = FALSE;
              fSwitchedOn = TRUE;
            }
            break;
          case MODEMSTATE_SIEMENS_POWERON:
          default: // MODEMSTATE_SIEMENS_URCCONFIGs
            SwitchUrcState(pCmd);
            UnlockPowerState();
            break;
        }
        break;

      default: // MODEMSTATE_SIEMENS_URCCONFIGs
        switch (m_dwModemState) {
          case MODEMSTATE_SIEMENS_POWEROFF:
            if (!TurnOnModule(pCmd, FALSE)) {
              UnlockPowerState();
            }
            fSwitchedOn = TRUE;
            // Store the urc state as new initial urc state
            m_dwInitUrcState = pCmd->GetCmd();
            break;
          case MODEMSTATE_SIEMENS_AIRPLANE:
            if (!SwitchActiveFlightMode(FALSE)) {
              UnlockPowerState();
            }
            if (m_fOffToAirplane) {
              // If we had been switched from off to airplane mode we have to repeat the initialization
              m_dwInitUrcState = pCmd->GetCmd();
              WaitAndLockPowerState();
              if (!StartReinitialization(pCmd)) {
                UnlockPowerState();
              }
              m_fOffToAirplane = FALSE;
              fSwitchedOn = TRUE;
            } else {
              WaitPowerState();
              SwitchUrcState(pCmd);
            }
            break;
          case MODEMSTATE_SIEMENS_POWERON:
          default: // MODEMSTATE_SIEMENS_URCCONFIGs
            SwitchUrcState(pCmd);
            UnlockPowerState();
            break;
        }
        break;
    }

    // If we've been switched on generate the equipment state changed notification
    // before the wait to show the "!" icon immediately
    EnterCriticalSection(&m_csPowerState);
    if (!m_fPowerOffForced && fSwitchedOn && ((dwLastEquipmentState != GetEquipmentFromModemState(m_dwModemState)) || !pCmd->IsPowerCmd())) {
      GenerateEquipmentNotification(pCmd, GetEquipmentFromModemState(m_dwModemState));
    }
    LeaveCriticalSection(&m_csPowerState);

    // Wait for the power operation to finish
    WaitPowerState();

    EnterCriticalSection(&m_csPowerState);

    // Set power state for GetEquipmentState()
    m_dwOldModemState = m_dwModemState;

    // Generate the equipment state changed notification
    if (!m_fPowerOffForced && !fSwitchedOn && ((dwLastEquipmentState != GetEquipmentState()) || !pCmd->IsPowerCmd())) {
      GenerateEquipmentNotification(pCmd , GetEquipmentState());
    }

    fBlock = FALSE;
    fUnblock= FALSE;
    fEmpty = FALSE;
    fClrRTS = FALSE;
    if (pCmd->IsPowerCmd() && !m_fPowerOffForced) {
      // Block further command handling on power states D3 and below
#ifdef SIEMENS_SMARTFON
      if ((pCmd->GetNewPowerState() >= D3) && (pCmd->GetOldPowerState() <= D2)) {
#else // SIEMENS_SMARTFON
      if ((pCmd->GetNewPowerState() >= D2) && (pCmd->GetOldPowerState() <= D1)) {
#endif // SIEMENS_SMARTFON
        if (m_dwModemState == MODEMSTATE_SIEMENS_POWEROFF) {
          // If we've been switched off wait until the command queues are empty
          fEmpty = TRUE;
        }
        fBlock = TRUE;
      }
      if ((pCmd->GetNewPowerState() <= D2) && (pCmd->GetOldPowerState() >= D3)) {
        fUnblock = TRUE;
      }
    }

    if ((pCmd->GetNewPowerState() >= D3) && (m_dwModemState != MODEMSTATE_SIEMENS_POWEROFF)) {
      fClrRTS = TRUE;
    }

    LeaveCriticalSection(&m_csPowerState);

    // Empty command queues if required
    if (fEmpty) {
      EmptyATCmdQueues();
    }

    // Block further command handling if required
    if (fBlock) {
      GetRilDevice(NULL)->BlockCommandHandling();
    }

    // Unblock further command handling if required
    if (fUnblock) {
      GetRilDevice(NULL)->UnblockCommandHandling();
    }

#ifdef RIL_ENABLE_RING_ON_INCOMMING_DATA
    if (pCmd->IsPowerCmd() && IS_URCSTATE(m_dwModemState) && (pCmd->GetNewPowerState() >= D3)) {
      for (COM_PORT_TYPE i = 0; i < NUMBER_OF_AVAILABLE_PORTS; i++) {
        CComHandle* pComDevice = GetRilDevice(NULL)->GetComDevice(i);
        if (pComDevice) {
          DCB dcb;
          if (pComDevice->VirtGetCommState(&dcb)) {
            dcb.fRtsControl = RTS_CONTROL_DISABLE;
            if (pComDevice->VirtSetCommState(&dcb)) {
              pComDevice->VirtEscapeCommFunction(CLRRTS);
            }
          }
        }
      }
    }
#endif

    // Clear hardware RTS signal to block further data
    if (fClrRTS && !fRTSCleared) {
      fRTSCleared = TRUE;
      SendMuxCmd(IOCTL_MPX_CLR_HW_RTS);
    }

    // Execute next command if it is a late RIL_EQSTATE_MINIMUM call
    Sleep(0);
    EnterCriticalSection(&m_csPowerState);
    if (pCmd->IsPowerCmd() && pCmd->IsBlocking()) {
      CPowerCmd*  pNextCmd;
      if (m_CmdQueue.Peek(pNextCmd)) {
        if (pNextCmd) {
          if (pNextCmd->IsEquipmentStateCmd()) {
            RILRetailTrace((TEXT("RilDrv: Catch up late equipment state call\r\n")));
            pNextCmd->SetFinishEvent(pCmd->InheritFinishEvent());
          }
        }
      }
    }
    m_fOngoing = FALSE;
    LeaveCriticalSection(&m_csPowerState);

    // Stop the system idle timer reset
    SwitchIdleTimerReset(FALSE);

    if ((pCmd->GetNewPowerState() >= D2) && (pCmd->GetOldPowerState() <= D1)) {
      SwitchUnattendedMode(FALSE);
    }

    // Delete the command
    delete pCmd;
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread to handle the power command queue.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::CmdQueueThread(LPVOID lpParameter) {
CPowerManager* pHandle = (CPowerManager*)lpParameter;

  if (!pHandle) {
    return -2;
  }

  if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {
    return -3;
  }

  return pHandle->CmdQueueHandler();
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the internal pointer to CRilHandle or the pointer stored in the
// passed CRilInstanceHandle.
//
// Params:
//  pHandle: Pointer to a CRilInstanceHandle.
//
// Return:
//  The internal stored pointer to CRilHandle if the passed pointer to
//  CRilInstanceHandle is NULL, otherwise the CRilHandle pointer form
//  CRilInstanceHandle.
//
//////////////////////////////////////////////////////////////////////////////
CRilHandle* CPowerManager::GetRilDevice(CRilInstanceHandle* pHandle) {
  return (pHandle ? pHandle->GetDevice() : m_pRilHandle);
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the name of a power command for debug trace.
//
// Params:
//  dwCmd: The id of the command we're looking for.
//
// Return:
//  The name of the command we're looking for.
//
//////////////////////////////////////////////////////////////////////////////
TCHAR* CPowerManager::GetCmdName(DWORD dwCmd) {
  switch(dwCmd) {
    case MODEMSTATE_SIEMENS_FORCE_POWEROFF          :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_FORCE_POWEROFF));
    case MODEMSTATE_SIEMENS_POWEROFF                :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_POWEROFF));
    case MODEMSTATE_SIEMENS_AIRPLANE                :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_AIRPLANE));
    case MODEMSTATE_SIEMENS_POWERON                 :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_POWERON));
    case MODEMSTATE_SIEMENS_URCCONFIG_CALL          :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_URCCONFIG_CALL));
    case MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS      :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS));
    case MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS_REG  :  return(PWR_STATE_TXT(MODEMSTATE_SIEMENS_URCCONFIG_CALL_SMS_REG));
  }
  return TEXT("Unkown Power Command");
}

